import csv
import json
import os
import platform
import resource
from typing import Annotated, Optional
from datetime import datetime, timedelta

from hashlib import md5
from fastapi import APIRouter, Depends, BackgroundTasks, Request, Body
from fastapi.responses import FileResponse

from sanren.utils import get_current_active_user, Helper
from sanren.extensions import ExtRedis, scheduler
from application.http.models import OemModel, CodeModel
from application.http import schemas
from application.config import appSettings
from application.tasks import order_task, push_task


router = APIRouter(prefix='/code/orders', tags=['Code'])
module_name = '码管理模块 - 生码单'


@router.get('/batchs', response_model=schemas.BaseApiListOut)
async def get_order_batchs(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    brand_id: Optional[str | int] = None,
    code: Optional[str] = None,
):
    """
        码管理 码批次列表
    """

    objs = CodeModel.Order.where('status', 2)

    if brand_id:
        objs = objs.where('brand_id', brand_id)

    if code:
        objs = objs.where('company_code', code)

    objs = objs.order_by('id', 'desc').all()

    return {'data': objs.serialize(), 'meta': {'total': objs.count()}}


@router.get('/add_info', response_model=schemas.BaseApiOut)
async def get_order_before_info(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
):
    """
        生码单前信息
    """

    res = CodeModel.Order.order_by('batch_num', 'desc').first()
    if res is None:
        obj_setting = CodeModel.Setting.where('key', 'diy_batch_sn').first()
        if obj_setting is None:
            batch_num = 1
        else:
            batch_num = int(obj_setting.value)
    else:
        batch_num = res.batch_num + 1

    obj_len = CodeModel.Setting.where('key', 'diy_batch_length').first()
    num_len = int(obj_len.value) if obj_len else 4
    batch_sn = Helper.batch_sn_encode(num=batch_num, num_length=num_len)

    return {'data': batch_sn}


@router.post('/get_code_info', response_model=schemas.BaseApiOut)
async def get_code_info(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    post: dict = Body()
):
    """
        获取生码单已经生码状况
    """

    code = post['company_code']
    if code is None or code == '':
        return schemas.BaseApiOut(code=1, message='请选择对应企业 code')

    if post['info_type'] == 'serial_code':  # 流水号
        data = get_product_serial_code_info(params=post)
    elif post['info_type'] == 'small_code':  # 刮刮码 - 小标
        data = get_product_small_code_info(params=post)
    elif post['info_type'] == 'security_code':  # 防伪码
        data = get_product_security_code_info(params=post)
    else:
        return schemas.BaseApiOut(code=1, message='目前只支持流水号、刮刮码-小标、防伪码查询')

    return schemas.BaseApiOut(data=data)


@router.post('/remarks/{id}', response_model=schemas.BaseApiOut)
async def edit_remark(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
    post: dict = Body()
):
    """
        生码单 编辑备注
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    try:
        obj.remarks = post['remarks']
        obj.save()

        print('操作成功')
        return {}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.post('/cancel/{id}', response_model=schemas.BaseApiOut)
async def order_cancel(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
):
    """
        生码单 取消生码
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    try:
        obj.status = 3
        obj.error_reason = '管理员手动取消生码单'
        obj.save()

        print('操作成功')
        return {}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.post('/generation/{id}', response_model=schemas.BaseApiOut)
async def order_generation(
    current_user: Annotated[object, Depends(get_current_active_user)],
    background_tasks: BackgroundTasks,
    request: Request,
    id: int,
):
    """
        生码单 开始生码
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')
    if obj.status != 0 and obj.status != 4:
        return schemas.BaseApiOut(code=1, message='生码单只有末开始和错误单能进行生码操作')

    # 检查码表并创建
    CodeModel.get_code_model(obj.company_code)

    try:
        # 生码
        job = scheduler.enqueue(
            order_task.generation_job,
            args=[obj.id],
            job_id=f'order_{obj.id}',
            description=f'生码单-{obj.id}',
            timeout=43200)

        # 更新生码状态 为 1 开始生码
        obj.status = 1
        obj.save()

        return {'message': '操作成功', 'data': {
            'job_id': job.get_id(),
            'job_status': job.get_status(),
        }}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.post('/push/{id}', response_model=schemas.BaseApiOut)
async def order_push(
    current_user: Annotated[object, Depends(get_current_active_user)],
    background_tasks: BackgroundTasks,
    request: Request,
    id: int,
):
    """
        生码单 推送生码单到 OEM 码库
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')
    if obj.status != 2:
        return schemas.BaseApiOut(code=1, message='生码单只有生码成功的才能进行推送码操作')

    try:
        # 生码
        job = scheduler.enqueue(
            push_task.push_job,
            args=[obj.id],
            job_id=f'order_{obj.id}',
            description=f'推送码单-{obj.id}',
            timeout=16600)

        return {'message': '操作成功', 'data': {
            'job_id': job.get_id(),
            'job_status': job.get_status(),
        }}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


def enable_code_status(*args, **kwargs):
    id = args[0]
    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    if obj.status != 2:
        return schemas.BaseApiOut(code=1, message='只有生码成功的码批次才能启禁用')

    # 码表
    company_code = obj.company_code
    Code = CodeModel.get_code_model(company_code)

    # status 0 未启用 1 启用 2 禁用
    Code.where('batch_num', obj.batch_num).update({'status': 1})

    obj.code_enable = 1
    obj.save()


@router.post('/enable/{id}', response_model=schemas.BaseApiOut)
async def order_enable(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
):
    """
        生码单 启用码
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    if obj.status != 2:
        return schemas.BaseApiOut(code=1, message='只有生码成功的码批次才能启禁用')

    # # 码表
    # company_code = obj.company_code
    # Code = CodeModel.get_code_model(company_code)

    try:
        # # status 0 未启用 1 启用 2 禁用
        # Code.where('batch_num', obj.batch_num).update({'status': 1})

        # obj.code_enable = 1
        # obj.save()
        # 生码
        job = scheduler.enqueue(
            enable_code_status,
            args=[obj.id],
            job_id=f'order_enable_{obj.id}',
            description=f'生码单启用-{obj.id}',
            timeout=16600)

        return {'message': '操作成功', 'data': {
            'job_id': job.get_id(),
            'job_status': job.get_status(),
        }}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.post('/export/{id}', response_model=schemas.BaseApiOut)
async def order_export(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
    post: dict = Body(),
):
    """
        生码单 导出请求

        v9 变更
        导出变更为异步请求
    """

    obj = CodeModel.Order.find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    try:
        obj_download = OemModel.Download.create({
            'type': 1,
            'params': json.dumps(post),
            'position': 0,
            'status': 0,
            'admin_id': current_user.id,
            'name': obj.batch_sn + '-' + str(obj.counts) + '-码包',
            'remarks': post.get('remarks', ''),
        })

        obj_download = obj_download.fresh()

        # 异步处理任务启动
        job = scheduler.enqueue(
            order_task.export_job,
            args=[obj_download.id],
            job_id=f'order_export_{obj_download.id}',
            description=f'生码单导出码包-{obj_download.id}',
            timeout=16600,
            kwargs={**post}
        )

        return {'message': '操作成功', 'data': {'id': obj_download.fresh().id, 'job_id': job.get_id(), 'job_status': job.get_status()}}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')

    # key_str = json.dumps(post, sort_keys=True).encode("utf-8")
    # key = md5(key_str).hexdigest()

    # print(key, post)

    # # 缓存 key 5分钟
    # redis = ExtRedis().instance()
    # redis.set(key, key_str, ex=60 * 60 * 24)

    # # 返回download_url
    # return schemas.BaseApiOut(data={
    #     'download_url': f'//{appSettings.web_host}/api/code/orders/download/{key}'
    # })


@router.get('/download/{token}', response_model=schemas.BaseApiOut)
async def order_download(
    request: Request,
    token: str,
):
    # 限制内存使用量
    # 3 GB
    maxsize = 3 * (1024 * 1024 * 1024 * 1024)
    rlimit = resource.RLIMIT_RSS if platform.system() == 'Darwin' else resource.RLIMIT_AS
    soft, hard = resource.getrlimit(rlimit)
    resource.setrlimit(rlimit, (maxsize, hard))

    redis = ExtRedis().instance()
    params_str = redis.get(token)
    if params_str is None:
        return schemas.BaseApiOut(code=1, message='找不到此记录')
    params = json.loads(params_str)

    order = CodeModel.Order.find(params['id'])
    if order is None:
        return schemas.BaseApiOut(code=1, message='找不到此记录')

    # 导出字段配置
    field_list = params['field_list']
    fields = field_list.split(',')
    print(fields)
    # 前缀
    url_prefix = params['url_prefix']
    # 2022-02-21
    # if url_prefix:
    #     url_prefix = url_prefix[:-1] if url_prefix.endswith('/') else url_prefix
    # 流水号前缀
    serial_prefix = params['serial_prefix']
    serial_suffix = params['serial_suffix']
    # 类型
    file_type = params['file_type']

    # 码表
    Code = CodeModel.get_code_model(order.company_code)
    # txt csv 字段根据提交过来的元素和顺序
    # codes = CodeModel.query.filter_by(batch_sn=order.batch_sn).order_by(CodeModel.id.asc()).all()

    _file_name = order.batch_sn + '-' + str(order.counts)
    if not os.path.exists(appSettings.export_path):
        os.makedirs(appSettings.export_path)
    file_name = _file_name + '.' + file_type
    save_file_path = appSettings.export_path + '/' + file_name

    def fetch_in_batches(batch_size):
        # 初始化一个批次计数器
        count = 0
        while True:
            # 使用session.query(Model).offset(count*batch_size).limit(batch_size)生成一个查询
            # 使用for循环迭代这个查询，因为它是惰性执行的
            for item in Code.where('batch_num', order.batch_num).order_by('id', 'asc').offset(count * batch_size).limit(batch_size).get():
                # 使用yield生成每一个结果
                yield item

            # 增加计数器
            count += 1

            # 如果没有更多的结果，则退出for循环
            if Code.where('batch_num', order.batch_num).order_by('id', 'asc').offset(count * batch_size).limit(batch_size).get().count() == 0:
                break

    def write_csv():
        # 1. 创建文件对象
        df = open(save_file_path, 'w', encoding='utf-8')
        # 2. 基于文件对象构建 csv写入对象
        csv_writer = csv.writer(df)
        # 3. 构建列表头
        csv_writer.writerow(format_code_header(fields))
        # 4. 写入csv文件内容
        # for item in codes:
        for item in fetch_in_batches(100000):
            row = format_code(fields, item)
            csv_writer.writerow(row)
        # 5. 关闭文件
        df.close()

    def format_code_header(fields):
        headers = {
            'big_code': '大标',
            'middle_code': '中标',
            'small_code': '刮刮码',
            'serial_code': '流水号',
            'security_code': '防伪码',
            'verify_code': '验证码',
            'prefix_serial_code': '流水号',
            'prefix_serial_code_ewm': '流水二维码',
            'prefix_security_code': '二维码',
        }
        write_data = []
        for field in fields:
            if field in headers.keys():
                write_data.append(headers[field])
        return write_data

    def format_code(fields, data):
        write_data = []
        data = data.serialize()
        for field in fields:
            if field in data:
                write_data.append(data[field])
            elif field == 'prefix_serial_code':
                serial_str = serial_prefix + data['serial_code'] + serial_suffix
                write_data.append(serial_str)
            elif field == 'prefix_serial_code_ewm':
                serial_str = url_prefix + serial_prefix + data['serial_code'] + serial_suffix
                write_data.append(serial_str)
            elif field == 'prefix_security_code':
                # 2022-02-21
                if order.query_type == 3:
                    # url = url_prefix + '/' + data['security_code']
                    url = url_prefix + data['security_code']
                else:
                    # url = url_prefix + '/' + data['batch_sn'] + '-' + data['security_code']
                    url = url_prefix + data['batch_sn'] + '-' + data['security_code']
                write_data.append(url)
        return write_data

    # 生成文件
    write_csv()

    return FileResponse(save_file_path, filename=file_name)


@router.get('', response_model=schemas.BaseApiListOut)
async def get_orders(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    page_params: schemas.PageParams = Depends(),
    status: Optional[str | int] = None,
    code: Optional[str] = None,
    keyword: Optional[str] = None,
):
    """
        码管理 扫码列表
    """

    objs = CodeModel.Order.with_('brand')

    if code:
        objs = objs.where('company_code', code)

    if status:
        objs = objs.where('status', status)

    if keyword:
        objs = objs.where(
            lambda query: query.where(
                'batch_sn', 'like', f'%{keyword}%'
            ).or_where(
                'company_name', 'like', f'%{keyword}%'
            ).or_where(
                'order_sn', 'like', f'%{keyword}%'
            )
        )

    objs = objs.order_by('id', 'desc').paginate(page_params.pageSize, page_params.page)

    return objs.serialize()


@router.post('', response_model=schemas.BaseApiOut)
async def add_order(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    post: dict = Body()
):
    """
        增加生码单
    """

    # 归属企业信息
    company = OemModel.Company.where('code', post['company_code'].lower()).first()
    if company is None:
        return schemas.BaseApiOut(code=1, message='企业不存在')

    # 产品信息
    if 'good_code' in post and post['good_code'] is not None and post['good_code'] != '' and len(post['good_code']) > 0:
        good = OemModel.Good.where('code', post['company_code'].lower()).where('good_code', post['good_code']).first()
        if good is None:
            return schemas.BaseApiOut(code=1, message='找不到商品信息')
    else:
        post['good_code'] = None

    exist_order = CodeModel.Order.where('batch_sn', post['batch_sn']).first()
    if exist_order is not None:
        return schemas.BaseApiOut(code=1, message='此批次号已经被使用')

    if post['big_status'] == 0 and post['middle_status'] == 0 \
            and post['small_status'] == 0 and post['security_status'] == 0:
        return schemas.BaseApiOut(code=1, message='大/中/小/防伪码必须有一个为启用状态')

    if post['verify_status'] == 1 and post['security_status'] != 1:
        return schemas.BaseApiOut(code=1, message='防伪码才能生验证码')

    # 批次信息
    batch_num = Helper.batch_sn_decode(post['batch_sn'])

    # 大小码量计算
    big_total = 0
    big_counts = 0
    middle_total = 0
    middle_counts = 0
    small_total = 0
    small_counts = 0
    counts = int(post['counts'])
    if int(post['type']) == 1:  # 套标
        big_counts = 1
        middle_counts = int(post['middle_counts'])
        small_counts = int(post['small_counts'])

        # 套标量计算
        if big_counts > 0 and middle_counts > 0 and small_counts > 0:
            big_middle_small_counts = big_counts * middle_counts * small_counts
        elif big_counts > 0 and small_counts > 0:
            big_middle_small_counts = big_counts * small_counts
        else:
            big_middle_small_counts = small_counts
        big_total = counts * big_counts
        middle_total = counts * middle_counts
        small_total = counts * big_middle_small_counts
    else:
        small_total = counts

    # 自定义流水
    if post['big_diy_status'] == 0:
        post['big_diy_value'] = 0
    if post['middle_diy_status'] == 0:
        post['middle_diy_value'] = 0
    if post['small_diy_status'] == 0:
        post['small_diy_value'] = 0
    if post['serial_diy_status'] == 0:
        post['serial_diy_value'] = 0

    try:
        # 创建生码单
        order = CodeModel.Order.create(
            # 生码单号
            order_sn=CodeModel.Order().create_order_sn(),
            # 验证方式
            query_type=post['query_type'],
            # 套标量
            big_counts=big_counts, middle_counts=middle_counts, small_counts=small_counts,
            # 总生码量
            big_total=big_total, middle_total=middle_total, small_total=small_total,
            # 基础信息
            company_code=company.code.lower(),
            company_name=company.name,
            remarks=post['remarks'] if 'remarks' in post and post['remarks'] != '' else None,
            # 类型 码量
            type=post['type'],
            counts=counts,
            # 批次
            batch_sn=post['batch_sn'],
            batch_num=batch_num,
            # 商品编码
            good_code=post['good_code'] if 'good_code' in post and post['good_code'] != '' else None,
            # 大标
            big_status=bool(post['big_status']),
            big_type=post['big_type'],
            big_length=post['big_length'],
            big_diy_status=bool(post['big_diy_status']),
            big_diy_value=post['big_diy_value'],
            # 中标
            middle_status=bool(post['middle_status']),
            middle_type=post['middle_type'],
            middle_length=post['middle_length'],
            middle_diy_status=bool(post['middle_diy_status']),
            middle_diy_value=post['middle_diy_value'],
            # 小标 刮刮码
            small_status=bool(post['small_status']),
            small_type=post['small_type'],
            small_length=post['small_length'],
            small_diy_status=bool(post['small_diy_status']),
            small_diy_value=post['small_diy_value'],
            # 小标 刮刮码前后缀
            small_prefix=post['small_prefix'] if 'small_prefix' in post and post['small_prefix'] != '' else None,
            small_suffix=post['small_suffix'] if 'small_suffix' in post and post['small_suffix'] != '' else None,
            # 流水号
            serial_status=bool(post['serial_status']),
            serial_type=post['serial_type'],
            serial_length=post['serial_length'],
            serial_diy_status=bool(post['serial_diy_status']),
            serial_diy_value=post['serial_diy_value'],
            # 流水号前后缀
            serial_prefix=post['serial_prefix'] if 'serial_prefix' in post and post['serial_prefix'] != '' else None,
            serial_suffix=post['serial_suffix'] if 'serial_suffix' in post and post['serial_suffix'] != '' else None,
            # 防伪码
            security_status=bool(post['security_status']),
            security_type=post['security_type'],
            security_length=post['security_length'],
            # 验证码
            verify_status=bool(post['verify_status']),
            verify_type=post['verify_type'],
            verify_length=post['verify_length'],
            # 导出链接配置
            url_prefix=post['url_prefix'] if 'url_prefix' in post and post['url_prefix'] != '' else None,
            url_suffix=post['url_suffix'] if 'url_suffix' in post and post['url_suffix'] != '' else None,
            # 默认状态
            status=0
        )

        print('操作成功', order.fresh().id)
        return {'code': 0, 'message': '创建成功'}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.put('/{id}', response_model=schemas.BaseApiOut)
async def update_order(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
    post: dict = Body()
):
    """
        更新生码单
    """

    order = CodeModel.Order.find(id)
    if order is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    if post['big_status'] == 0 and post['middle_status'] == 0 \
            and post['small_status'] == 0 and post['security_status'] == 0:
        return schemas.BaseApiOut(code=1, message='大/中/小/防伪码必须有一个为启用状态')

    if post['verify_status'] == 1 and post['security_status'] != 1:
        return schemas.BaseApiOut(code=1, message='防伪码才能生验证码')

    # 产品信息
    if 'good_code' in post and post['good_code'] is not None and post['good_code'] != '' and len(post['good_code']) > 0:
        good = OemModel.Good.where('code', post['company_code'].lower()).where('good_code', post['good_code']).first()
        if good is None:
            return schemas.BaseApiOut(code=1, message='找不到商品信息')
    else:
        post['good_code'] = None

    if order.status in [1, 2]:
        return schemas.BaseApiOut(code=1, message='生码中或已生码的单不能再进行修改。')

    # 大小码量计算
    big_total = 0
    big_counts = 0
    middle_total = 0
    middle_counts = 0
    small_total = 0
    small_counts = 0
    counts = int(post['counts'])
    if int(post['type']) == 1:  # 套标
        big_counts = 1
        middle_counts = int(post['middle_counts'])
        small_counts = int(post['small_counts'])

        # 套标量计算
        if big_counts > 0 and middle_counts > 0 and small_counts > 0:
            big_middle_small_counts = big_counts * middle_counts * small_counts
        elif big_counts > 0 and small_counts > 0:
            big_middle_small_counts = big_counts * small_counts
        else:
            big_middle_small_counts = small_counts
        big_total = counts * big_counts
        middle_total = counts * middle_counts
        small_total = counts * big_middle_small_counts
    else:
        small_total = counts

    try:
        # 更新生码单
        order.update({
            'big_total': big_total,
            'middle_total': middle_total,
            'small_total': small_total,
            'big_counts': big_counts,
            'middle_counts': middle_counts,
            'small_counts': small_counts,
            'type': post['type'],
            'query_type': post['query_type'],
            'counts': counts,
            'good_code': post['good_code'] if 'good_code' in post and post['good_code'] != '' else None,
            # 大标
            'big_status': bool(post['big_status']),
            'big_type': post['big_type'],
            'big_length': post['big_length'],
            'big_diy_status': bool(post['big_diy_status']),
            'big_diy_value': post['big_diy_value'],
            # 中标
            'middle_status': bool(post['middle_status']),
            'middle_type': post['middle_type'],
            'middle_length': post['middle_length'],
            'middle_diy_status': bool(post['middle_diy_status']),
            'middle_diy_value': post['middle_diy_value'],
            # 小标 刮刮码
            'small_status': bool(post['small_status']),
            'small_type': post['small_type'],
            'small_length': post['small_length'],
            'small_diy_status': bool(post['small_diy_status']),
            'small_diy_value': post['small_diy_value'],
            # 小标 刮刮码前后缀
            'small_prefix': post['small_prefix'] if 'small_prefix' in post and post['small_prefix'] != '' else None,
            'small_suffix': post['small_suffix'] if 'small_suffix' in post and post['small_suffix'] != '' else None,
            # 流水号
            'serial_status': bool(post['serial_status']),
            'serial_type': post['serial_type'],
            'serial_length': post['serial_length'],
            'serial_diy_status': bool(post['serial_diy_status']),
            'serial_diy_value': post['serial_diy_value'],
            # 流水号前后缀
            'serial_prefix': post['serial_prefix'] if 'serial_prefix' in post and post['serial_prefix'] != '' else None,
            'serial_suffix': post['serial_suffix'] if 'serial_suffix' in post and post['serial_suffix'] != '' else None,
            # 防伪码
            'security_status': bool(post['security_status']),
            'security_type': post['security_type'],
            'security_length': post['security_length'],
            # 验证码
            'verify_status': bool(post['verify_status']),
            'verify_type': post['verify_type'],
            'verify_length': post['verify_length'],
            # 导出链接配置
            'url_prefix': post['url_prefix'] if 'url_prefix' in post and post['url_prefix'] != '' else None,
            'url_suffix': post['url_suffix'] if 'url_suffix' in post and post['url_suffix'] != '' else None,
            # 默认状态
            'remarks': post['remarks'] if 'remarks' in post and post['remarks'] != '' else None,
        })

        return {'code': 0, 'message': '更新成功'}
    except Exception as e:
        return schemas.BaseApiOut(code=1, message=f'操作失败: {str(e)}')


@router.get('/{id}', response_model=schemas.BaseApiOut)
async def get_order(
    current_user: Annotated[object, Depends(get_current_active_user)],
    request: Request,
    id: int,
):
    """
        生码单详情
    """

    obj = CodeModel.Order.with_('brand').with_('good').find(id)
    if obj is None:
        return schemas.BaseApiOut(code=1, message='此生码单不存在')

    return {'data': obj.serialize()}


def get_product_small_code_info(params):
    obj_order = CodeModel.Order.where(
        'company_code', params['company_code']
    ).where(
        'small_type', params['small_type']
    ).where(
        'small_length', params['small_length']
    ).where(
        'status', 2
    ).sum('small_total as gen_total').first().gen_total

    total = 10**int(params['small_length']) - 1
    # 获取步长
    step = CodeModel.Setting.where('key', 'scratch_step_' + str(params['small_length'])).first()
    if step and step is not None:
        total = total / int(step.value) + 1
    else:
        # 默认步长10
        total = int(total / 10) + 1

    gen_total = 0
    if obj_order and obj_order is not None:
        gen_total = obj_order

    msg = '可正常生码'
    if gen_total + int(params['counts']) > int(total):
        msg = '已经超出生码位数，建议更换长度或码类型'

    return {
        'total': int(total),
        'gen_total': int(gen_total),
        'msg': msg,
    }


def get_product_security_code_info(params):
    pass


def get_product_serial_code_info(params):
    # 0 流水号
    last_serial_max = CodeModel.Order.where(
        'company_code', params['company_code']
    ).where(
        'serial_type', 0
    ).select_raw(
        'max(serial_serial_end) as serial_serial_end'
    )

    # 有商品信息，从头开始计算流水号
    if 'good_code' in params and params['good_code'] is not None and params['good_code'] != '' and len(params['good_code']) > 0:
        last_serial_max = last_serial_max.where('good_code', params['good_code'])
    else:
        last_serial_max = last_serial_max.where_null('good_code')
    # 取最大流水号值
    last_serial_max = last_serial_max.first().serial_serial_end
    max_serial = 0
    if last_serial_max is not None:
        # 格式化
        max_serial = int(last_serial_max)

    if int(params['serial_diy_status']) == 1:
        serial_diy_value = int(params['serial_diy_value'])
        # 自定义 流水号
        number = max_serial + 1 if max_serial and max_serial >= serial_diy_value else serial_diy_value
    else:
        # 默认 流水号
        number = max_serial + 1 if max_serial else 1

    f = '{:0>' + str(params['serial_length']) + '}'
    start = f.format(number)
    end_int = number + int(params['counts']) - 1

    msg = '可正常生码'
    if end_int > 10**int(params['serial_length']) - 1:
        msg = '已经超出生码位数，建议更换长度或码类型'
    end = f.format(end_int)

    return {
        'start': start,
        'end': end,
        'msg': msg,
    }
